package it.aekidna.cleverplatypus.gui.components.columnsbrowser
{
	import as3reflect.Type;

	import flash.events.Event;
	import flash.events.FocusEvent;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.ui.Keyboard;
	import flash.utils.Dictionary;
	import flash.utils.getQualifiedClassName;

	import it.aekidna.cleverplatypus.domain.IHasChildren;
	import it.aekidna.cleverplatypus.gui.layout.ILayoutManagerHandleDetector;
	import it.aekidna.cleverplatypus.gui.layout.ResizeManager;

	import mx.binding.utils.BindingUtils;
	import mx.collections.ArrayCollection;
	import mx.containers.Canvas;
	import mx.containers.HBox;
	import mx.controls.Image;
	import mx.controls.List;
	import mx.core.ClassFactory;
	import mx.core.IFactory;
	import mx.events.CollectionEvent;
	import mx.events.CollectionEventKind;
	import mx.events.ResizeEvent;
	import mx.logging.ILogger;
	import mx.logging.Log;
	import mx.rpc.events.ResultEvent;

	public class ColumnsBrowserColumn extends HBox implements ILayoutManagerHandleDetector
	{
		private var _childView : ColumnsBrowserColumn;
		private var _list : List;
		private var _listHBox : Canvas;
		private var _resizeHandle : Image;
		[Embed( source="/resources/images/columnsBrowserResizeHandle.png" )]
		private var _resizeHandleIcon : Class;

		private static const LOGGER : ILogger = Log.getLogger( getQualifiedClassName( ColumnsBrowserColumn ).replace( /:+/g, "." ));

		private var _parentBrowser : ColumnsBrowserColumn;
		private var _itemRenderer : IFactory;


		public var labelField : String = "label";


		public function get itemRenderer() : IFactory
		{
			return _itemRenderer;
		}


		public function set itemRenderer( inFactory : IFactory ) : void
		{
			_itemRenderer = inFactory;

			if( _itemRenderer )
			{
				var type : Type = Type.forClass( ClassFactory( _itemRenderer ).generator );

				if( type.getField( "columnPM" ) != null )
				{
					if( !ClassFactory( _itemRenderer ).properties )
						ClassFactory( _itemRenderer ).properties = {};
					ClassFactory( _itemRenderer ).properties.columnPM = columnPModel;
				}
			}

			if( _childView )
				_childView.itemRenderer = _itemRenderer;

			if( _list )
				_list.itemRenderer = _itemRenderer;
		}


		[Bindable]
		public var columnPModel : ColumnsBrowserColumnPM;


		public var defaultWidth : int = 180;

		private var renderers : Dictionary = new Dictionary( true );
		private var _manuallyResize : Boolean;


		public function ColumnsBrowserColumn()
		{
			super();
			addEventListener( "ITEM_RENDERER_TEXT_RESIZE", onItemRendererTextResize );
			addEventListener( ResizeEvent.RESIZE, onResize );
		}


		private function onResize( inEvent : ResizeEvent ) : void
		{
			if( ResizeManager.getManager().objectIsResizing( _listHBox ))
				_manuallyResize = true;
		}


		private function onItemRendererTextResize( inEvent : ResultEvent ) : void
		{
			if( !_manuallyResize )
			{
				inEvent.stopImmediatePropagation();

				if( !ResizeManager.getManager().objectIsResizing( _listHBox ))
				{
					renderers[ inEvent.target ] = int( inEvent.result );
					var maxSize : int = 0;

					for each( var size : int in renderers )
					{
						maxSize = Math.max( size, maxSize );
					}
					_listHBox.width = Math.min( 500, Math.max( maxSize + 24, _listHBox.minWidth ));
				}
			}
		}


		override protected function createChildren() : void
		{
			super.createChildren();
			setStyle( "horizontalGap", 0 );
			setStyle( "backgroundColor", 0xdddddd );
			_list = new ReducedVerticalScrollBarList();
			_list.setStyle( "borderStyle", "none" );
			_list.setStyle( "alternatingItemColors", []);
			_list.percentHeight = 100;
			_list.percentWidth = 100;
			_list.addEventListener( Event.CHANGE, onListChange );
			columnPModel.dataProvider.addEventListener( CollectionEvent.COLLECTION_CHANGE, onDataProviderCollectionChange, false, int.MIN_VALUE );
			_list.labelField = labelField;
			_list.dataProvider = columnPModel.dataProvider;
			_list.verticalScrollPolicy = "on";
			_list.itemRenderer = itemRenderer;
			_list.addEventListener( KeyboardEvent.KEY_UP, onListKeyUp );
			_list.addEventListener( FocusEvent.FOCUS_IN, onListFocusChange );
			_list.addEventListener( FocusEvent.FOCUS_OUT, onListFocusChange );
			_resizeHandle = new Image();
			_resizeHandle.source = _resizeHandleIcon;
			_resizeHandle.setStyle( "right", 0 );
			_resizeHandle.setStyle( "bottom", 0 );
			_resizeHandle.doubleClickEnabled = true;
			_resizeHandle.addEventListener( MouseEvent.DOUBLE_CLICK, onResizeHandlerDoubleClick );
			BindingUtils.bindProperty( _list, "dataProvider", columnPModel, "dataProvider" );
			BindingUtils.bindSetter( onDataProviderChange, columnPModel, "dataProvider" );
			_listHBox = new Canvas();
			_listHBox.minWidth = _listHBox.width = defaultWidth;
			_listHBox.percentHeight = 100;
			_listHBox.addChild( _list );
			_listHBox.addChild( _resizeHandle );
			ResizeManager.getManager().enableResize( _listHBox, defaultWidth, 100, true, true, this );
			addChild( _listHBox );
		}


		private function onDataProviderChange( inValue : ArrayCollection ) : void
		{
			if( _childView )
			{
				removeChildView();
			}
		}


		private function onAdded( inEvent : Event ) : void
		{
			if( inEvent.target is ClassFactory( _list.itemRenderer ).generator )
			{
				inEvent.stopImmediatePropagation();
				renderers[ inEvent.target ] = 0;
			}
		}


		private function onResizeHandlerDoubleClick( inEvent : MouseEvent ) : void
		{
			_manuallyResize = false;
		}


		private function onListKeyUp( inEvent : KeyboardEvent ) : void
		{

			switch( inEvent.keyCode )
			{
				case Keyboard.RIGHT:
					if( _list && _list.selectedItems.length == 1 && _list.selectedItem is IHasChildren )
					{
						if( _childView._list.dataProvider.length > 0 )
						{
							_childView._list.setFocus();
							_childView._list.selectedIndex = 0;
							_childView.onListChange( null );
						}
					}
					break;
				case Keyboard.LEFT:
					if( _parentBrowser )
					{
						_list.selectedIndex = -1;
						_parentBrowser._list.setFocus();

						if( _childView )
						{
							removeChildView();
						}
					}
			}
		}


		private function onListFocusChange( inEvent : FocusEvent ) : void
		{
			if( inEvent.type == FocusEvent.FOCUS_IN )
				_list.setStyle( "selectionColor", 0x7FCEFF );
			else
				_list.setStyle( "selectionColor", 0xadc1cc );
		}


		private function onDataProviderCollectionChange( inEvent : CollectionEvent ) : void
		{
			if( inEvent.kind == CollectionEventKind.REFRESH )
			{
				var items : Array = [];
				var notFound : Boolean;

				for each( var index : int in _list.selectedIndices )
				{
					if( columnPModel.dataProvider.contains( columnPModel.dataProvider.toArray()[ index ]))
						items.push( index );
					else
						notFound = true;
				}

				if( notFound )
					_list.selectedIndices = items;

				if( _list.selectedIndices.length == 0 )
				{
					if( _childView != null )
						removeChildView();
				}
			}
		}


		private function onListChange( inEvent : Event ) : void
		{
			columnPModel.selectedItems = _list.selectedItems;

			if( columnPModel.selectedItems.length == 1 && ArrayCollection( columnPModel.selectedItems ).getItemAt( 0 ) is IHasChildren )
			{
				if( _childView == null )
				{
					createChildView();
				}
				else
				{
					_childView.columnPModel.dataProvider = IHasChildren( _list.selectedItem ).children
				}
				columnPModel.pModel.selectedBranch = IHasChildren( _list.selectedItem );
			}
			else
			{
				if( _childView != null )
				{
					removeChildView();
				}
			}
		}


		private function createChildView() : void
		{
			_childView = new ColumnsBrowserColumn();
			_childView.columnPModel = columnPModel.pModel.createChild();
			_childView.percentHeight = 100;
			_childView.labelField = labelField;
			_childView._parentBrowser = this;
			_childView.itemRenderer = itemRenderer;
			addChildAt( _childView, 1 );
		}


		private function removeChildView() : void
		{
			var column : ColumnsBrowserColumn = ColumnsBrowserColumn( removeChildAt( 1 ));
			columnPModel.pModel.destroyChild( column.columnPModel );
			_childView = null;
		}


		public function detectLayoutManagerHandle( inEvent : MouseEvent ) : int
		{
			if( _resizeHandle.hitTestPoint( inEvent.stageX, inEvent.stageY ))
				return ResizeManager.SIDE_RIGHT;
			else
				return ResizeManager.SIDE_OTHER;
		}

	}
}

